package coderead.plugin;
/**
 * @Copyright 源码阅读网 http://coderead.cn
 */

import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.ui.SearchTextField;
import com.intellij.ui.WindowMoveListener;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextField;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.HtmlPanel;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.components.BorderLayoutPanel;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.function.Consumer;

/**
 * @author 鲁班大叔
 * @date 2021
 */
public abstract class AbstractSearchPopupUI extends BorderLayoutPanel implements Disposable {
    public static final Color LINE_COLOR = new JBColor(Gray._189, Gray._100);
    public static final Color TAB_ACTIVE_BACKGROUND = new JBColor(Gray._222, new Color(85, 90, 94));
    public static final Color INFORMATION_COLOR = new JBColor(new Color(253, 254, 226), new Color(0x4d4f51));
    public static final Color LABEL_BACKGROUND = new JBColor(Gray._234, new Color(69, 73, 74));


    private static final int MINIMAL_SUGGESTIONS_LIST_HEIGHT = 100;
    protected final Project myProject;
    protected SearchTextField mySearchField;
    protected JPanel suggestionsPanel;
    protected Tree myResultsList;
    protected final List<ViewTypeListener> myViewTypeListeners = ContainerUtil.createLockFreeCopyOnWriteList();
    protected ViewType myViewType = ViewType.SHORT;
    protected DetailHtmlLabel myHintLabel;

    public AbstractSearchPopupUI(Project project) {
        myProject = project;
    }


    public abstract Tree createList();


    protected abstract JPanel createTopLeftPanel();


    protected abstract JPanel createSettingsPanel();


    protected abstract String getInitialHint();

    protected void installScrollingActions() {
        TreeUtil.installActions(myResultsList);
        create(e -> TreeUtil.moveDown(myResultsList))
                .registerCustomShortcutSet(KeyEvent.VK_DOWN, 0, mySearchField);
        create(e -> TreeUtil.moveUp(myResultsList))
                .registerCustomShortcutSet(KeyEvent.VK_UP, 0, mySearchField);

    }

    protected DumbAwareAction create(Consumer<AnActionEvent> action) {
        return new DumbAwareAction() {
            @Override
            public void actionPerformed(AnActionEvent e) {
                action.accept(e);
            }
        };
    }


    public void init() {
        myResultsList = createList();
        JPanel topLeftPanel = createTopLeftPanel();
        JPanel settingsPanel = createSettingsPanel();
        mySearchField = createSearchField();
        suggestionsPanel = createSuggestionsPanel();
        myResultsList.setFocusable(false);
        myResultsList.setFocusCycleRoot(true);
        installScrollingActions();
        JPanel topPanel = new JPanel(new BorderLayout());
        topPanel.setOpaque(false);
        topPanel.add(topLeftPanel, BorderLayout.WEST);
        topPanel.add(settingsPanel, BorderLayout.EAST);
        topPanel.add(mySearchField, BorderLayout.SOUTH);
        WindowMoveListener moveListener = new WindowMoveListener(this);
        topPanel.addMouseListener(moveListener);
        topPanel.addMouseMotionListener(moveListener);
        addToTop(topPanel);
        addToCenter(suggestionsPanel);
    }

    private SearchTextField createSearchField() {
        SearchTextField searchTextField = new SearchTextField(false);
        Border line = JBUI.Borders.customLine(LINE_COLOR, 1, 0, 1, 0);
        Border border = searchTextField.getTextEditor().getBorder();
        Insets insets = border.getBorderInsets(searchTextField.getTextEditor());
        Border empty = JBUI.Borders.empty(insets.top, insets.left, insets.bottom, insets.right);
        Border merge = JBUI.Borders.merge(line, empty, false);
        searchTextField.getTextEditor().setBorder(merge);
        searchTextField.getTextEditor().setFocusTraversalKeysEnabled(false);
        return searchTextField;
    }


    protected void updateViewType(ViewType viewType) {
        if (myViewType != viewType) {
            myViewType = viewType;
            myViewTypeListeners.forEach(listener -> listener.suggestionsShown(viewType));
        }
    }

    private JPanel createSuggestionsPanel() {
        JPanel pnl = new JPanel(new BorderLayout());
        pnl.setOpaque(false);
        JScrollPane resultsScroll = new JBScrollPane(myResultsList);
        resultsScroll.setBorder(null);
        resultsScroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        pnl.add(resultsScroll, BorderLayout.CENTER);
        myHintLabel = createHint();
        pnl.add(myHintLabel, BorderLayout.SOUTH);
        return pnl;
    }


    private DetailHtmlLabel createHint() {
        DetailHtmlLabel label = new DetailHtmlLabel();
        label.setBorder(JBUI.Borders.empty(5));
        label.setBackground(LABEL_BACKGROUND);
        label.setOpaque(true);
        label.setAndUpdateText(getInitialHint());
        label.updateUI();
        return label;
    }

    protected JBTextField getSearchField() {
        return mySearchField.getTextEditor();
    }

    @Override
    public Dimension getMinimumSize() {
        Dimension size = calcPrefSize(ViewType.SHORT);
        if (getViewType() == ViewType.FULL) {
            size.height += MINIMAL_SUGGESTIONS_LIST_HEIGHT;
        }
        return size;
    }

    @Override
    public Dimension getPreferredSize() {
        return calcPrefSize(myViewType);
    }

    public Dimension getExpandedSize() {
        return calcPrefSize(ViewType.FULL);
    }

    private Dimension calcPrefSize(ViewType viewType) {
        Dimension size = super.getPreferredSize();
        if (viewType == ViewType.SHORT) {
            size.height -= suggestionsPanel.getPreferredSize().height;
        }
        return size;
    }

    public ViewType getViewType() {
        return myViewType;
    }

    public enum ViewType {FULL, SHORT}

    public interface ViewTypeListener {
        void suggestionsShown(ViewType viewType);
    }

    protected static class DetailHtmlLabel extends HtmlPanel {
        private String detailText = "";

        @NotNull
        @Override
        protected String getBody() {
            return detailText == null ? "" : detailText;
        }

        public void setAndUpdateText(String detailText) {
            this.detailText = detailText;
        }

        @Override
        public void setBody(@NotNull String text) {
            if (text.isEmpty()) {
                setText("");
            } else {
                setText("<html><head>" +
                        UIUtil.getCssFontDeclaration(
                                UIUtil.getLabelFont().deriveFont((float) (UIUtil.getLabelFont().getSize() - 2)),
                                UIUtil.getLabelForeground(), null, null) +
                        "</head><body>" +
                        text +
                        "</body></html>");
            }
        }
    }

    public Project getMyProject() {
        return myProject;
    }
}
